﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Wise.Util
{
    public class ObjectHelper:HelperBase<ObjectHelper>
    {
        /// <summary>
        /// 创建对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T CreateInstance<T>()
        {
            return (T) CreateInstance(typeof(T));
        }

        /// <summary>
        /// 创建对象
        /// </summary>
        /// <returns></returns>
        public static Object CreateInstance(Type type)
        {
            if (type.GetConstructors().Any(x => x.GetParameters().Length == 0)
                        || type.IsValueType)
            {
                return Activator.CreateInstance(type);
            }
            else if (type == typeof(String))
            {
                return String.Empty;
            }
            else
            {
                throw new NotImplementedException(string.Format("类型{0}没有定义无参构造函数", type.FullName));
            }
        }
        
        /// <summary>
        /// 判断当前类型是否继承于目标类型
        /// 目标类型是否可以隐式转换成当前类型
        /// </summary>
        /// <param name="judgeType">当前类型</param>
        /// <param name="targetType">目标类型</param>
        /// <returns></returns>
        internal static bool IsInheritFrom(Type judgeType, Type targetType)
        {
            return targetType.IsAssignableFrom(judgeType);
        }

        internal static string GetPrimaryKeyOrIndexField(Type type)
        {
            return CacheHelper.Get<string,Type>(string.Format("PK_IDX_{0}", type.FullName), CreatePrimaryKeyOrIndexField, type);
        }
        static int judgeIsPK(string name)
        {
            if (string.Equals("Id", name, StringComparison.CurrentCultureIgnoreCase))
            {
                return 2;
            }
            else if (name.EndsWith("Id", StringComparison.CurrentCultureIgnoreCase))
            {
                return 3;
            }
            return 10086;
        }

        static bool judgeIsPK(Attribute a)
        {
            Type aType = a.GetType();
            string aName = aType.Name;
            if (aName == "PrimaryKey" || aName == "PrimaryKeyAttribute")
            {
                return true;
            }
            else if (aName == "Key" || aName == "KeyAttribute")
            {
                return true;
            }
            else if (aName == "Index" || aName == "IndexAttribute")
            {
#if DOTNET46
                        var aAttrs = aType.GetProperties();
                        CustomAttributeData cad = p.PropertyType.GetCustomAttributesData().FirstOrDefault(x => x.AttributeType == aType);
                        CustomAttributeNamedArgument cana = default(CustomAttributeNamedArgument);
                        foreach (var x in cad.NamedArguments)
                        {
                            if (x.MemberName == "IsClustered")
                                cana = x;
                        }
                        //聚集索引优先
                        if (cana.TypedValue != null && Object.Equals(cana.TypedValue.Value, true))
                        {
                            return true;
                        }
#else
                return true;
#endif
            }
            else if (aName == "ColumnAttribute" || aName == "Column")
            {
#if DOTNET46
                        var aAttrs = aType.GetProperties();
                        CustomAttributeData cad = p.PropertyType.GetCustomAttributesData().FirstOrDefault(x => x.AttributeType == aType);
                        CustomAttributeNamedArgument cana = default(CustomAttributeNamedArgument);
                        foreach (var x in cad.NamedArguments)
                        {
                            if (x.MemberName == "IsPrimaryKey")
                                cana = x;
                        }
                        if (cana.TypedValue != null && Object.Equals(cana.TypedValue.Value, true))
                        {
                            field1st = p.Name;
                        }
#else
                return false;
#endif
            }
            return false;
        }

        private static string CreatePrimaryKeyOrIndexField(Object objType)
        {
            Type type = (Type)objType;
            var props = GetObjectPropertyMap(type);
            //候选键
            string field1st = null, field2nd = null, field3th = null;
            foreach (PropertyInfo p in props)
            {
                #region Member
                Object[] atts = p.PropertyType.GetCustomAttributes(true);
                foreach (Attribute a in atts)
                {
                    if (judgeIsPK(a))
                        return p.Name;
                }
                switch(judgeIsPK(p.Name))
                {
                    case 1:
                        field1st = p.Name;
                        break;
                    case 2:
                        field2nd = p.Name;
                        break;
                    case 3:
                        field3th = p.Name;
                        break;
                }
                #endregion
            }
            var fields = GetObjectFieldMap(type);
            foreach (FieldInfo p in fields)
            {
                #region Member
                Object[] atts = p.FieldType.GetCustomAttributes(true);
                foreach (Attribute a in atts)
                {
                    if (judgeIsPK(a))
                        return p.Name;
                }
                switch (judgeIsPK(p.Name))
                {
                    case 1:
                        field1st = p.Name;
                        break;
                    case 2:
                        field2nd = p.Name;
                        break;
                    case 3:
                        field3th = p.Name;
                        break;
                }
                #endregion
            }
            return field1st ?? field2nd ?? field3th;
        }

        private static List<string> ignoreTypes = new List<string>() {
            "System.Data.Entity.Infrastructure.ObjectReferenceEqualityComparer"
            ,"System.Object"
        };

        /// <summary>
        /// 获取属性映射
        /// </summary>
        /// <returns></returns>
        internal static List<PropertyInfo> GetObjectPropertyMap(Type type, bool noNeedWrite=false)
        {
            if (ignoreTypes.Contains(type.FullName)) return new List<PropertyInfo>();
            var rs = type.GetProperties()
                .Where(x => x.CanRead && (noNeedWrite || x.CanWrite))
                .Where(x => !string.IsNullOrEmpty(x.Name) && !x.Name.StartsWith("<"))
                .ToList();
            if (rs.Count == 0 && type.FullName.StartsWith("<"))
                return type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance)
                    .Where(x => x.CanRead && (noNeedWrite || x.CanWrite))
                     .Where(x => !x.Name.StartsWith("<"))
                     .ToList();
            else
                return rs;
        }

        internal static List<FieldInfo> GetObjectFieldMap(Type type, bool noNeedWrite=false)
        {
            if (ignoreTypes.Contains(type.FullName)) return new List<FieldInfo>();
            var rs = type.GetFields()
                .Where(x => noNeedWrite || (x.IsInitOnly == false && x.IsLiteral == false))
                 .Where(x => !x.Name.StartsWith("<"))
                 .ToList();
            if (rs.Count == 0 && type.FullName.StartsWith("<"))
                return type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
                    .Where(x => noNeedWrite || (x.IsInitOnly == false && x.IsLiteral == false))
                     .Where(x => !x.Name.StartsWith("<"))
                     .ToList();
            else
                return rs;
        }

        internal static object ChangeType(object value, Type type)
        {
            return value.ChangeTo(type);
        }


        /// <summary>
        /// 对象比较
        /// 尚未实现除string外的引用类型比较
        /// </summary>
        /// <param name="s"></param>
        /// <param name="t"></param>
        /// <returns></returns>
        public static new bool Equals(object s,object t)
        {
            if (s == null && t == null)
                return true;
            else if (s == null || t == null)
                return false;
            Type tS = s.GetType(), tT = t.GetType();
            if(tS!=tT)
            {
                tS = tS.Unpack();
                tT = tT.Unpack();
            }
            if(tS!=tT)
            {
                return false;
            }
            if (tS == typeof(String))
                return string.Equals(s, t);
            else if (tS.IsValueType)
                return Object.Equals(s, t);
            else
            {
                return Object.Equals(s, t);
            }
        }
    }
}
